<?php

/**
 * 
 * 
 * 对比简单工厂模式的优点是，您可以将其子类用不同的方法来创建一个对象。
 *       
 *    举一个简单的例子，这个抽象类可能只是一个接口。
 *       
 *      这种模式是「真正」的设计模式， 因为他实现了S.O.L.I.D原则中「D」的 「依赖倒置」。
 *       
 *  这意味着工厂方法模式取决于抽象类，而不是具体的类。 这是与简单工厂模式和静态工厂模式相比的优势。
 * 
 *   比如:数据库 mysql sqlser ，支付 ：支付宝，微信，银联。
 * 
 */
interface VehicleInterface
{

    public function setColor(string $rgb);
}

class CarMercedes implements VehicleInterface
{

    /**
     *
     * @var string
     */
    private $color;

    public function setColor(string $rgb)
    {
        $this->color = $rgb;
    }

    public function addAMGTuning()
    {
        // 在这里做额外的调整
    }
}

class CarFerrari implements VehicleInterface
{

    /**
     *
     * @var string
     */
    private $color;

    public function setColor(string $rgb)
    {
        $this->color = $rgb;
    }
}

class Bicycle implements VehicleInterface
{

    /**
     *
     * @var string
     */
    private $color;

    public function setColor(string $rgb)
    {
        $this->color = $rgb;
    }
}

abstract class FactoryMethod
{

    const CHEAP = 'cheap';

    const FAST = 'fast';

    abstract protected function createVehicle(string $type): VehicleInterface;

    public function create(string $type): VehicleInterface
    {
        $obj = $this->createVehicle($type);
        $obj->setColor('black');
        
        return $obj;
    }
}

class ItalianFactory extends FactoryMethod
{

    protected function createVehicle(string $type): VehicleInterface
    {
        switch ($type) {
            case parent::CHEAP:
                return new Bicycle();
            case parent::FAST:
                return new CarFerrari();
            default:
                throw new \InvalidArgumentException("$type is not a valid vehicle");
        }
    }
}

class GermanFactory extends FactoryMethod
{

    protected function createVehicle(string $type): VehicleInterface
    {
        switch ($type) {
            case parent::CHEAP:
                return new Bicycle();
            case parent::FAST:
                $carMercedes = new CarMercedes();
                // 我们可以从已知的的类中找到具体的交通工具
                $carMercedes->addAMGTuning();
                
                return $carMercedes;
            default:
                throw new \InvalidArgumentException("$type is not a valid vehicle");
        }
    }
}

(new GermanFactory())->create(FactoryMethod::CHEAP)->setColor("red");
(new ItalianFactory())->create(FactoryMethod::CHEAP)->setColor("blue");